#pragma once

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <cstring>
#include <functional>

#include "Log.hpp"
extern Log lg;

typedef std::function<std::string(const std::string&)> func_t;

// 枚举错误信息
enum 
{
    SOCKET_ERR=1,
    BIND_ERR
};

// 服务器默认端口号
uint16_t defaultport = 8081;
// 服务器默认ip
std::string defaultip = "0.0.0.0";

// 数据缓冲区大小
const int size = 1024;

class UdpServer
{
public:
    UdpServer(const uint16_t &port = defaultport, const std::string &ip = defaultip)
        :port_(port), ip_(ip), isrunning_(false)
    {}
    
    void Init()
    {
        // 1. 创建 udp socket
        sockfd_ = socket(AF_INET, SOCK_DGRAM, 0);
        if (sockfd_ < 0)
        {
            lg(Fatal, "socket create error, sockfd: %d" , sockfd_);
            exit(SOCKET_ERR);
        }
        lg(Info, "socket create success, sockfd: %d" , sockfd_);
        
        // 2. bind socket

        // 初始化 local
        struct sockaddr_in local;
        bzero(&local, sizeof(local)); // 清零 local
        local.sin_family = AF_INET; // 设置为 IPv4
        local.sin_port = htons(port_); // 需要保证这里的端口号是网络字节序列，因为该端口号是要给对方发送的
        // 1. string -> uint32_t 
        // 2. uint32_t必须是网络序列的
        local.sin_addr.s_addr = inet_addr(ip_.c_str()); 

        if(bind(sockfd_, (const struct sockaddr*)&local, sizeof(local)) < 0)
        {
            lg(Fatal,"bind error, errno: %d, err string: %s" , errno, strerror(errno));
            exit(BIND_ERR);
        }
        lg(Info, "bind socket success!");
    }

    void Run(func_t func)
    {
        // 设置服务器运行状态为 运行中
        isrunning_ = true;
        
        // 设置缓冲区
        char inbuffer[size];
        while(isrunning_)
        {
            // 输出型参数 client
            struct sockaddr_in client;
            socklen_t len = sizeof(client);

            // 从 inbuffer 中读取数据
            // sizeof(inbuffer)-1 意思是将 inbufffer 视为字符串
            // n 表示实际接收到了多少个字符
            // 同时获取 client 信息，便于之后的发送
            ssize_t n = recvfrom(sockfd_, inbuffer, sizeof(inbuffer)-1, 0, (struct sockaddr*)&client, &len);

            if(n < 0)
            {
                lg(Warning, "recvfrom error, errno: %d, err string: %s", errno, strerror(errno));
                continue;
            }
            inbuffer[n]= 0;

            //充当了一次数据的处理
            std::string info = inbuffer;
            std::string echo_string = func(info);

            // server 向 client 发送应答信息
            sendto(sockfd_, echo_string.c_str(), echo_string.size(), 0, (struct sockaddr*)&client, len);
        }
    }

    ~UdpServer()
    {
        if (sockfd_ > 0) close(sockfd_);
    }
private:
    int sockfd_;       // 网路文件描述符
    std::string ip_;   // 服务器ip
    uint16_t port_;    // 服务器进程的端口号
    bool isrunning_;   // 服务器运行状态
};
